﻿using System.Collections;
using System.Collections.Generic;
using TypeDescriptor;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace TypeDescriptorUintTest
{


    /// <summary>
    ///This is a test class for TypeExtensionTest and is intended
    ///to contain all TypeExtensionTest Unit Tests
    ///</summary>
    [TestClass]
    public class TypeExtensionTest
    {
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        #region Additional test attributes

        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //

        #endregion


        /// <summary>
        ///A test for ToString
        ///</summary>
        [TestMethod]
        public void ToStringTest()
        {
            Type type = typeof(A);
            const string expected = "TypeDescriptorUintTest.A";
            string actual = type.ToString(null);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void ToStringTest_1()
        {
            Type type = typeof(A);
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.FullName);
            const string expected = "TypeDescriptorUintTest.AWrapper";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void ToStringTest_2()
        {
            Type type = typeof(List<A>);
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "List<AWrapper>";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void ToStringTest_3()
        {
            Type type = typeof(List<Tuple<int, string, double, A>>);
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "List<Tuple<int, string, double, AWrapper>>";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void ToStringTest_4()
        {
            Type type = typeof(A[, ,]);
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "AWrapper[,,]";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToStringTest_5()
        {
            Type type = typeof(A).GetMethod("M1").GetParameters()[0].ParameterType;
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "int";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void ToStringTest_6()
        {
            Type type = typeof(A).GetMethod("M2").GetParameters()[0].ParameterType;
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "int";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void ToStringTest_8()
        {
            Type type = typeof(A).GetMethod("M4").GetParameters()[0].ParameterType;
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "Tuple<int, double, int>";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToStringTest_7()
        {
            Type type = typeof(A).GetMethod("M5").ReturnType;
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "T";
            string actual = type.ToString(func);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetMethodConstraint_00()
        {
            var medthod = typeof(A).GetMethod("M10");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }
        [TestMethod]
        public void GetMethodConstraint_01()
        {
            var medthod = typeof(A).GetMethod("M7");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : struct";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void GetMethodConstraint_02()
        {
            var medthod = typeof(A).GetMethod("M6");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : class";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetMethodConstraint_03()
        {
            var medthod = typeof(A).GetMethod("M8");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : IEnumerable<ClassCleanupAttributeWrapper>";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void GetMethodConstraint_04()
        {
            var medthod = typeof(A).GetMethod("M9");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : new()";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetMethodConstraint_05()
        {
            var medthod = typeof(A).GetMethod("M5");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : AWrapper";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void GetMethodConstraint_06()
        {
            var medthod = typeof(TestGenMethodInfo).GetMethod("G1");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : class\r\nwhere U : struct";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }


        [TestMethod]
        public void GetMethodConstraint_07()
        {
            var medthod = typeof(TestGenMethodInfo).GetMethod("G2");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : IComparableWrapper, IEnumerableWrapper\r\nwhere U : List<T>";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void GetMethodConstraint_08()
        {
            var medthod = typeof(TestGenMethodInfo).GetMethod("G3");
            Func<Type, string> func = t => string.Format("{0}Wrapper", t.Name);
            const string expected = "where T : IComparableWrapper, IEnumerableWrapper\r\nwhere U : Tuple<int, T>";
            string actual = medthod.GetMethodConstraint(func);
            Assert.AreEqual(expected, actual);
        }
    }

    public class A
    {
        public int A1 { get; set; }

        public List<int> A2 { get; set; }

        public List<Tuple<int, string, double>> A3 { get; set; }

        public Type M1(ref int i)
        {
            return i.GetType();
        }


        public Type M2(out int i)
        {
            i = 0;
            return i.GetType();
        }


        public Type M4(ref Tuple<int, double, int> i)
        {
            return i.GetType();
        }
        public T M5<T>(out int i) where T : A
        {
            i = 0;
            return default(T);

        }

        public T M6<T>(out int i) where T : class
        {
            i = 0;
            return default(T);

        }

        public T M7<T>(out int i) where T : struct
        {
            i = 0;
            return default(T);

        }

        public T M8<T>(out int i) where T : IEnumerable<ClassCleanupAttribute>
        {
            i = 0;
            return default(T);

        }

        public T M9<T>(out int i) where T : new()
        {
            i = 0;
            return default(T);

        }

        public T M10<T>(out int i)
        {
            i = 0;
            return default(T);

        }
    }

    public class TestGenMethodInfo
    {
        public void G1<T, U>()
            where T : class
            where U : struct
        {

        }
        public void G2<T, U>()
            where T : IComparable, IEnumerable
            where U : List<T>
        {

        }


        public void G3<T, U>()
            where T : IComparable, IEnumerable
            where U : Tuple<int, T>
        {

        }
    }

    public interface IMyInterface
    {
    }
}
